#include "../common/dispather.h"
#include "../client/rpc_client.h"
#include "rpc_route.h"
#include "rpc_register.h"
#include "rpc_topic.h"

namespace rpc
{
    namespace server
    {
        class RegisterServer
        {
        public:
            using ptr = std::shared_ptr<RegisterServer>;
            RegisterServer(int port)
                : _pd_manager(std::make_shared<PDManager>()), _dispather(std::make_shared<dispather>())
            {
                auto service_cb = std::bind(&PDManager::onServiceRequest, _pd_manager.get(), std::placeholders::_1, std::placeholders::_2);
                _dispather->registerHandler<ServiceRequest>(MType::REQ_SERVICE, service_cb);

                _server = ServerFactory::create(port);
                auto messgae_cb = std::bind(&dispather::onMessage, _dispather.get(), std::placeholders::_1, std::placeholders::_2);
                _server->setMessageCallback(messgae_cb);

                auto close_cb = std::bind(&RegisterServer::onConnShutdown, this, std::placeholders::_1);
                _server->setCloseCallback(close_cb);
            }
            void start()
            {
                _server->start();
            }

        private:
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                _pd_manager->onConnShutdown(conn);
            }

        private:
            PDManager::ptr _pd_manager;
            dispather::ptr _dispather;
            BaseServer::ptr _server;
        };
        class RpcServer
        {
        public:
            using ptr = std::shared_ptr<RpcServer>;
            RpcServer(const Address &access_addr, bool enableRegistry = false, const Address &registry_server_addr = Address())
                : _enableRegister(enableRegistry),
                  _access_addr(access_addr),
                  _router(std::make_shared<rpc::server::RpcRouter>()),
                  _dispather(std::make_shared<rpc::dispather>())
            {
                if (enableRegistry)
                {
                    _reg_client = std::make_shared<client::RegisterClient>(registry_server_addr.first, registry_server_addr.second);

                    auto rpc_cb = std::bind(&RpcRouter::onRpcRequest, _router.get(), std::placeholders::_1, std::placeholders::_2);
                    _dispather->registerHandler<RpcRequest>(MType::REQ_RPC, rpc_cb);
                    _server = ServerFactory::create(access_addr.first);
                    auto message_cb = std::bind(&dispather::onMessage, _dispather.get(), std::placeholders::_1, std::placeholders::_2);
                    _server->setMessageCallback(message_cb);
                }
            }
            void registerMethod(const ServerDescribe::ptr &service)
            {
                if (_enableRegister)
                {
                    _reg_client->registerMthod(service->method(), _access_addr);
                }
                _router->registerMethod(service);
            }
            void start()
            {
                _server->start();
            }

        private:
            bool _enableRegister;
            Address _access_addr;
            client::RegisterClient::ptr _reg_client;
            RpcRouter::ptr _router;
            dispather::ptr _dispather;
            BaseServer::ptr _server;
        };
        class TopicServer
        {
        public:
            using ptr = std::shared_ptr<TopicServer>;
            TopicServer(int port)
                : _topic_manager(std::make_shared<TopicManager>()), _dispather(std::make_shared<dispather>())
            {
                auto topic_req = std::bind(&TopicManager::onTopicquest, _topic_manager.get(), std::placeholders::_1, std::placeholders::_2);
                _dispather->registerHandler<TopicRequest>(MType::REQ_TOPIC, topic_req);

                _server = ServerFactory::create(port);

                auto message_cb = std::bind(&dispather::onMessage, _dispather.get(), std::placeholders::_1, std::placeholders::_2);
                _server->setMessageCallback(message_cb);
                auto close_cb = std::bind(&TopicServer::onConnShutdown, this, std::placeholders::_1);
                _server->setCloseCallback(close_cb);
            }
            void start()
            {
                _server->start();
            }

        private:
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                _topic_manager->onShutdown(conn);
            }

        private:
            TopicManager::ptr _topic_manager;
            dispather::ptr _dispather;
            BaseServer::ptr _server;
        };
    }
}